package com.library.management.repository;

import com.library.management.entity.Book;
import com.library.management.entity.BorrowRecord;
import com.library.management.entity.User;
import com.library.management.enums.BorrowStatus;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 借阅记录数据访问层接口
 * 提供借阅记录相关的数据库操作
 *
 * @author 开发者
 * @version 1.0
 * @since 2025-10-20
 */
@Repository
public interface BorrowRecordRepository extends JpaRepository<BorrowRecord, Long> {

    // ========== 用户相关查询 ==========

    /**
     * 根据用户查找借阅记录
     *
     * @param user 用户
     * @return 借阅记录列表
     */
    List<BorrowRecord> findByUser(User user);

    /**
     * 根据用户ID查找借阅记录
     *
     * @param userId 用户ID
     * @return 借阅记录列表
     */
    List<BorrowRecord> findByUserId(Long userId);

    /**
     * 根据用户和状态查找借阅记录
     *
     * @param user 用户
     * @param status 借阅状态
     * @return 借阅记录列表
     */
    List<BorrowRecord> findByUserAndStatus(User user, BorrowStatus status);

    // ========== 图书相关查询 ==========

    /**
     * 根据图书查找借阅记录
     *
     * @param book 图书
     * @return 借阅记录列表
     */
    List<BorrowRecord> findByBook(Book book);

    /**
     * 根据图书ID查找借阅记录
     *
     * @param bookId 图书ID
     * @return 借阅记录列表
     */
    List<BorrowRecord> findByBookId(Long bookId);

    // ========== 状态相关查询 ==========

    /**
     * 根据借阅状态查找记录
     *
     * @param status 借阅状态
     * @return 借阅记录列表
     */
    List<BorrowRecord> findByStatus(BorrowStatus status);

    /**
     * 查找当前借阅中的记录（包括借阅中、逾期、已续借）
     *
     * @return 当前借阅记录列表
     */
    @Query("SELECT br FROM BorrowRecord br WHERE br.status IN ('BORROWED', 'OVERDUE', 'RENEWED')")
    List<BorrowRecord> findCurrentBorrowRecords();

    /**
     * 查找已逾期的借阅记录
     *
     * @return 逾期记录列表
     */
    @Query("SELECT br FROM BorrowRecord br WHERE br.status = 'OVERDUE'")
    List<BorrowRecord> findOverdueRecords();

    // ========== 时间相关查询 ==========

    /**
     * 查找借阅日期在指定范围内的记录
     *
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 借阅记录列表
     */
    List<BorrowRecord> findByBorrowDateBetween(LocalDateTime startDate, LocalDateTime endDate);

    /**
     * 查找应还日期在指定范围内的记录
     *
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 借阅记录列表
     */
    List<BorrowRecord> findByDueDateBetween(LocalDateTime startDate, LocalDateTime endDate);

    /**
     * 查找即将到期的借阅记录（在指定天数内到期）
     *
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 即将到期记录列表
     */
    @Query("SELECT br FROM BorrowRecord br WHERE br.dueDate BETWEEN :startDate AND :endDate AND br.status = 'BORROWED'")
    List<BorrowRecord> findDueSoonRecords(@Param("startDate") LocalDateTime startDate,
                                          @Param("endDate") LocalDateTime endDate);

    // ========== 复杂查询方法 ==========

    /**
     * 统计用户的借阅次数
     *
     * @param userId 用户ID
     * @return 借阅次数
     */
    long countByUserId(Long userId);

    /**
     * 统计图书的被借阅次数
     *
     * @param bookId 图书ID
     * @return 借阅次数
     */
    long countByBookId(Long bookId);

    /**
     * 查找用户当前借阅的图书数量
     *
     * @param userId 用户ID
     * @return 当前借阅数量
     */
    @Query("SELECT COUNT(br) FROM BorrowRecord br WHERE br.user.id = :userId AND br.status IN ('BORROWED', 'OVERDUE', 'RENEWED')")
    long countCurrentBorrowsByUserId(@Param("userId") Long userId);

    /**
     * 检查用户是否已借阅某本图书且未归还
     *
     * @param userId 用户ID
     * @param bookId 图书ID
     * @return true-已借阅未归还，false-未借阅或已归还
     */
    @Query("SELECT COUNT(br) > 0 FROM BorrowRecord br WHERE br.user.id = :userId AND br.book.id = :bookId AND br.status IN ('BORROWED', 'OVERDUE', 'RENEWED')")
    boolean existsByUserIdAndBookIdAndNotReturned(@Param("userId") Long userId,
                                                  @Param("bookId") Long bookId);

    /**
     * 根据用户和图书查找未归还的借阅记录
     *
     * @param userId 用户ID
     * @param bookId 图书ID
     * @return 借阅记录
     */
    @Query("SELECT br FROM BorrowRecord br WHERE br.user.id = :userId AND br.book.id = :bookId AND br.status IN ('BORROWED', 'OVERDUE', 'RENEWED')")
    Optional<BorrowRecord> findActiveBorrowByUserAndBook(@Param("userId") Long userId,
                                                         @Param("bookId") Long bookId);

    // ========== 分页查询 ==========

    /**
     * 分页查询用户的借阅记录
     *
     * @param user 用户
     * @param pageable 分页参数
     * @return 分页借阅记录
     */
    Page<BorrowRecord> findByUser(User user, Pageable pageable);

    /**
     * 分页查询指定状态的借阅记录
     *
     * @param status 借阅状态
     * @param pageable 分页参数
     * @return 分页借阅记录
     */
    Page<BorrowRecord> findByStatus(BorrowStatus status, Pageable pageable);

    // ========== 统计查询 ==========

    /**
     * 统计每日借阅数量
     *
     * @param startDate 开始日期
     * @param endDate 结束日期
     * @return 借阅统计
     */
    @Query("SELECT DATE(br.borrowDate), COUNT(br) FROM BorrowRecord br WHERE br.borrowDate BETWEEN :startDate AND :endDate GROUP BY DATE(br.borrowDate) ORDER BY DATE(br.borrowDate) DESC")
    List<Object[]> countBorrowsByDay(@Param("startDate") LocalDateTime startDate,
                                     @Param("endDate") LocalDateTime endDate);

    /**
     * 查找最受欢迎的图书（借阅次数最多的图书）
     *
     * @param limit 返回数量
     * @return 图书借阅统计
     */
    @Query("SELECT br.book, COUNT(br) as borrowCount FROM BorrowRecord br GROUP BY br.book ORDER BY borrowCount DESC")
    List<Object[]> findPopularBooks(@Param("limit") int limit);

    /**
     * 查找指定天数内的借阅记录
     *
     * @param startTime 开始时间
     * @return 借阅记录列表
     */
    @Query("SELECT br FROM BorrowRecord br WHERE br.borrowDate >= :startTime")
    List<BorrowRecord> findBorrowsInLastDays(@Param("startTime") LocalDateTime startTime);

    /**
     * 统计逾期记录数量
     *
     * @return 逾期记录数量
     */
    @Query("SELECT COUNT(br) FROM BorrowRecord br WHERE br.status = 'OVERDUE'")
    long countOverdueRecords();
}